#ifndef __M_SINK_H__
#define __M_SINK_H__
#include <memory>
#include <fstream>
#include <mutex>
#include <cassert>
#include <iostream>
#include "util.hpp"
namespace mylog{
class LogSink{
public:
  using ptr = std::shared_ptr<LogSink>;//智能指针别名
 LogSink() {}
 virtual ~LogSink() {}
 //纯虚函数，将日志写入到指定位置
 virtual void log(const char *data, size_t len) = 0;
};

//落地方向——标准输出
class StdoutSink:public LogSink{
public:
void log(const char *data, size_t len)override{
    std::cout.write(data,len); //不会因为\0结束
}
};
//落地方向——指定文件
class FileSink:public LogSink{
    public:
    //构造时传入文件名，打开文件，并将文件操作句柄管理起来
    FileSink(const std::string pathname):_pathname(pathname) {
        //1.创建文件路径所在路径
        util::file::create_directory(util::file::path(_pathname));
        //2.创建并打开文件
        _ofs.open(_pathname,std::ios::binary|std::ios::app);//二进制模式&&追加模式
        assert(_ofs.is_open());

    }
    //将日志写入到指定文件
    void log(const char *data, size_t len)override{
        _ofs.write(data,len);
        assert(_ofs.good());//检查流是否处于良好状态
    }
    private:
std::string _pathname;
std::ofstream _ofs;
    };
//落地方向——滚动文件(文件大小)
class RollBySizeSink:public LogSink{
    public:
    RollBySizeSink(const std::string& basename,size_t max_size):
    _basename(basename),
    _max_size(max_size),
    _cur_size(0),
    _name_count(0){
        //1.创建文件路径所在路径
        util::file::create_directory(util::file::path(_basename));
        //2.创建文件名并打开文件
        std::string pathname=CreateNewFileName();
        _ofs.open(pathname,std::ios::binary|std::ios::app);//二进制模式&&追加模式
        assert(_ofs.is_open()); 
    }
    //将日志写入到滚动文件
    void log(const char *data, size_t len)override{
        if(_cur_size>_max_size){
        //1.关闭原来的文件,清零_cur_size
        _ofs.close();
        _cur_size=0;
        //2.创建文件名并打开文件
        std::string pathname=CreateNewFileName();
        _ofs.open(pathname,std::ios::binary|std::ios::app);//二进制模式&&追加模式
        assert(_ofs.is_open()); 
       }
       _ofs.write(data,len);
       assert(_ofs.good());//检查流是否处于良好状态
       _cur_size+=len;
    }
    private:
    //生成新文件名称
    std::string CreateNewFileName(){
       //获取当前时间，作为扩展文件名
       time_t t =util::Date::now();
       struct tm lt;
       localtime_r(&t,&lt);
       std::stringstream filename;
       filename<<_basename;
       filename<<lt.tm_year+1900;
       filename<<lt.tm_mon+1;
       filename<<lt.tm_mday;
       filename<<lt.tm_hour;
       filename<<lt.tm_min;
       filename<<lt.tm_sec;
       filename<<"-";
       filename<<_name_count++;
       filename<<".log";
       return filename.str();

    }
    private:
    //实际文件名=基础文件名+扩展文件名（以时间生成）
    std::string _basename;//基础文件名
    std::ofstream _ofs;//文件操作句柄
    size_t _max_size;//文件最大大小，超过就新建文件
    size_t _cur_size;//文件当前大小
    size_t _name_count;//应对一秒内产生几个文件的情况
    };

  
    class SinkFactory{
        public:
        SinkFactory(){}
        virtual ~SinkFactory(){}
        template<typename SinkType,typename ...Args>  //SinkType--指定类型 可变参数--不同类型需要传入的参数不同
        static LogSink::ptr Create(Args &&...args){
            return std::make_shared<SinkType>(std::forward<Args>(args)...);  //完美转发，保证属性不变
}                                                                            //(args)...对参数包的展开操作
    };
}

#endif